package com.ysd.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Arrays;
/**
 * redis分布式锁工具类,根据具体业务处理并发问题
 * 使用分布式锁无论处理成功与否都要释放锁。
 * @author Bai
 * @since 2023-10-08
 */
@Component
public class RedisLock {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    private static final String LOCK_PREFIX = "lock:";

    /**
     * 加锁
     *
     * @param key        锁定的键
     * @param value      值
     * @param expireTime 过期时间(毫秒)
     * @return 是否加锁成功
     */
    public boolean lock(String key, String value, long expireTime) {
        Boolean isSuccess = redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            // 创建锁键
            byte[] lockKey = redisTemplate.getStringSerializer().serialize(LOCK_PREFIX+ key);
            // 创建锁值
            byte[] lockValue = redisTemplate.getStringSerializer().serialize(value);
            // 尝试获取锁
            return connection.setNX(lockKey, lockValue) && connection.pExpire(lockKey, expireTime);
        });
        // 返回是否加锁成功
        return isSuccess != null && isSuccess;
    }

    /**
     * 解锁
     *
     * @param key   锁定的键
     * @param value 锁值
     */
    public void unlock(String key, String value) {
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            // 创建锁键
            byte[] lockKey = redisTemplate.getStringSerializer().serialize(LOCK_PREFIX + key);
            // 判断锁值是否匹配
            byte[] lockValue = redisTemplate.getStringSerializer().serialize(value);
            if (Arrays.equals(lockValue, connection.get(lockKey))) {
                // 如果锁值匹配，删除锁
                connection.del(lockKey);
            }
            return null;
        });
    }
}

